﻿#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING 1

#ifndef __UTIL_H__
#define __UTIL_H__

#include <experimental/filesystem>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <memory>
#include <sys/stat.h>

namespace Cloud
{
    namespace fs = std::experimental::filesystem;

    // 文件操作相关实用工具类
    class FileUtil
    {
    public:
        FileUtil(const std::string& filepath) :_filepath(filepath) {}

        // 获取文件大小
        int64_t FileSize()
        {
            struct stat st;
            if (stat(_filepath.c_str(), &st) < 0)
            {
                std::cerr << "Get fileSize fail!" << std::endl;
                return -1;
            }

            return st.st_size;
        }

        // 获取文件最后一次访问、创建、修改时间
        time_t LastAccTime()
        {
            struct stat st;
            if (stat(_filepath.c_str(), &st))
            {
                std::cerr << "Get access time fail!" << std::endl;
                return -1;
            }

            return st.st_atime;
        }
        time_t LastCreTime()
        {
            struct stat st;
            if (stat(_filepath.c_str(), &st))
            {
                std::cerr << "Get create time fail!" << std::endl;
                return -1;
            }

            return st.st_ctime;
        }
        time_t LastModTime()
        {
            struct stat st;
            if (stat(_filepath.c_str(), &st))
            {
                std::cerr << "Get modify time fail!" << std::endl;
                return -1;
            }

            return st.st_mtime;
        }

        // 获取文件名
        std::string FileName()
        {
            // 获取最后一个 '/'
            size_t pos = static_cast<size_t>(_filepath.find_last_of(R"(\/)")); // R"()" 字符不参与转义

            if (pos == std::string::npos)
                return _filepath;

            return _filepath.substr(pos + 1, _filepath.size() - pos);
        }

        // 获取文件 pos 位置起，长度为 len 的数据
        bool GetPosLen(std::string* body, size_t pos, size_t len)
        {
            // 如果读取的内容超出范围，则无法读取
            size_t fsize = static_cast<size_t>(this->FileSize());
            if (pos + len > fsize)
            {
                std::cerr << "FileSize less than Pos+Len!" << std::endl;
                return false;
            }

            // 打开文件进行读取
            std::ifstream ifs;
            ifs.open(_filepath, std::ios::binary);
            if (ifs.is_open() == false)
            {
                std::cerr << "Read open file error!" << std::endl;
                return false;
            }

            // 读取指针偏移至指定位置
            ifs.seekg(pos, std::ios::beg);
            body->resize(len); // 提前扩容

            // 读取指定长度的数据
            ifs.read(&((*body)[0]), len);
            if (ifs.good() == false)
            {
                std::cerr << "Read file fail!" << std::endl;
                ifs.close();
                return false;
            }

            ifs.close();
            return true;
        }

        // 获取文件所有数据
        bool GetContent(std::string* body)
        {
            // 复用接口
            size_t fsize = static_cast<size_t>(this->FileSize());
            return GetPosLen(body, 0, fsize);
        }

        // 设置文件内容
        bool SetContent(const std::string& body)
        {
            // 打开文件并进行写入
            std::ofstream ofs;
            ofs.open(_filepath, std::ios::binary);
            if (ofs.is_open() == false)
            {
                std::cerr << "Write open file fail!" << std::endl;
                return false;
            }

            // 写入数据
            ofs.write(body.c_str(), body.size());
            if (ofs.good() == false)
            {
                std::cerr << "Write file fail!" << std::endl;
                ofs.close();
                return false;
            }

            ofs.close();
            return true;
        }

        // 删除文件
        bool Remove()
        {
            if (Exists() == false)
            {
                std::cerr << "Remove file fail!" << std::endl;
                return false;
            }

            remove(_filepath.c_str());

            return true;
        }

        // 判断文件是否存在
        bool Exists()
        {
            return fs::exists(_filepath);
        }

        // 创建目录
        bool CreateDirectory()
        {
            // 如果目录存在，就不判断
            if (this->Exists() == true)
                return true;

            // 创建目录
            return fs::create_directories(_filepath);
        }

        // 浏览当前目录中的所有文件
        bool ScanDirectory(std::vector<std::string>* array)
        {
            // 迭代器遍历
            for (auto& p : fs::directory_iterator(_filepath))
            {
                // 如果是目录，就不进行统计（只记录文件）
                if (fs::is_directory(p) == true)
                    continue;

                // 记录信息
                array->push_back(fs::path(p).relative_path().string());
            }

            return true;
        }


    private:
        std::string _filepath;
    };
}

#endif